﻿#ifndef WidgetHelper_H
#define WidgetHelper_H

#include <QAction>
#include <QPair>
#include <QHash>
#include <functional>
#include <QPointer>
#include <QtCore/qglobal.h>

#include <ObjLib_global.h>


//控件property属性key，获得helper指针
#define HelperPointerKey "HelperPointer"
#define WidgetHelper_MimeType "widgethelper/mimetype"
#define ContainerEditableProperty "hmi_container_editable"

//便于转换控件类型
#define HELPER_W(Class) Class * const w = reinterpret_cast<Class *>(d_ptr->widget.data())

OBJLIB_EXPORT void setContainerEditable(QWidget *container, bool editable);
OBJLIB_EXPORT bool isContainerEditable(QWidget *container);

class QMenu;
class QWidget;
class QLineEdit;

enum WidgetHandleType
{
    WHT_LeftTop = 0,
    WHT_Top = 1,
    WHT_Left = 2,
    WHT_RightTop = 3,
    WHT_LeftBottom = 4,
    WHT_Right = 5,
    WHT_RightBottom = 6,
    WHT_Bottom = 7,

    WHT_First = WHT_LeftTop,
    WHT_Last = WHT_Bottom
};

struct HandleInfo {
    HandleInfo(Qt::CursorShape _shape = Qt::ArrowCursor, bool _visable = true, bool _valid = true):
        shape(_shape),visiable(_visable),valid(_valid) {}

    Qt::CursorShape shape;//光标形状
    bool visiable;//是否显示
    bool valid;//是否有效（是否可移动）
};

typedef QHash<WidgetHandleType, HandleInfo> HandleInfos;

class OBJLIB_EXPORT HelperData {
    friend class WidgetHelper;
public:
    HelperData(QWidget *_widget, const QString &_key);
    virtual ~HelperData();

    void init(WidgetHelper *_helper);
    void setWidgetReadOnly(bool b);

    bool editable;//是否可编辑（即选中，拖动大小等）
    bool selected;//是否选中
    bool visible;//是否显示（运行中）
    bool isWindow;//是否主窗体
    bool isContainer;//是否容器
    bool leftButtonPressed;//左键是否按下
    QPoint startPos;
    QList<QAction*> actions;
    HandleInfos handles;
    WidgetHelper *helper;
    QString key;
    QPointer<QWidget> widget;//绑定控件
    QList<QPair<QWidget*,bool>> childrenSet;//控件的子控件设置
    QList<QString> propertys;
};

/**
 * @brief The WidgetHelper class
 */
class OBJLIB_EXPORT WidgetHelper : public QObject
{
    Q_OBJECT
public:
    enum WidgetEditorType
    {
        WET_LineEdit,
    };
public:
    virtual ~WidgetHelper();
//    virtual QWidget *widgetEditor() const = 0;
    QString key() const {return d_ptr->key;}
    QWidget *widget() const {return d_ptr->widget;}
    bool selected() const {return d_ptr->selected;}
    bool editable() const {return d_ptr->editable;}
    bool isWindow() const {return d_ptr->isWindow;}
    bool isContainer() const {return d_ptr->isContainer;}

    QList<QAction*> actions() const {return d_ptr->actions;}
    HandleInfos handleInfos() const {return d_ptr->handles;}
    //用于获取可以设置的属性列表
    QList<QString> helperPropertys() const {return d_ptr->propertys;}
    virtual QVariant helperPropertyValue(const QString &name) const;

    virtual void setSelected(bool b);
    virtual void setEditable(bool b);
    virtual bool setHelperProperty(const QString &name, const QVariant &value);

    virtual WidgetHelper *clone() = 0;
    //容器专用
    virtual QList<WidgetHelper *> childHelpers(const QRect  &rect = QRect());
    virtual QMenu *addContextMenuActions(QMenu *popup) {return popup;}

    static WidgetHelper *getWidgetHelper(QWidget *w);
    static QList<QWidget*> helpersToWidgets(QList<WidgetHelper*> helpers);
    static QList<WidgetHelper*> widgetsToHelpers(QList<QWidget*> widgets);

    //当拖放发生时，鼠标释放事件可能丢失，需要调用此函数设置鼠标状态
    void setDropDone();

signals:
    void signal_mousePress();
    void signal_mouseRelease();
    void signal_mouseMove();
    void signal_mouseDblClick();
    void signal_startDrag(const QPoint &globalPos);
    void signal_helperPropertyChanged(const QString &name, const QVariant &value);

protected:
    bool eventFilter(QObject *watched, QEvent *event);

protected:
    QLineEdit *createEditor(QWidget *parent, const QRect &rect, const QString &text);

    WidgetHelper(HelperData *d, QObject *parent = nullptr);
    static void bindingHelperWidget(WidgetHelper *helper, QWidget *widget);
    HelperData *d_ptr;

    friend class HelperData;
};

typedef WidgetHelper* (*CreateHelperFunction)();
typedef const char* (*HelperKey)();

/**
 * @brief The WidgetHelperFactory class
 * @note 工厂类
 */
class OBJLIB_EXPORT WidgetHelperFactory
{
public:
    template<typename T>
    struct register_t
    {
        register_t(const QString& key)
        {
            WidgetHelperFactory::instance().m_creators[key] = [](){ return new T(); };
        }
    };

public:
    static WidgetHelperFactory& instance();

    static WidgetHelper* create(const QString &key);

    static QStringList keys();

private:
    void load();
    WidgetHelperFactory();
    WidgetHelperFactory(const WidgetHelperFactory&) = delete;
    WidgetHelperFactory(WidgetHelperFactory&&) = delete;
    WidgetHelperFactory& operator =(const WidgetHelperFactory&) = delete;
    QHash<QString, std::function<WidgetHelper*()>> m_creators;
};

#ifndef CLASS_NAME
#   define CLASS_NAME(Class) #Class
#endif

//宏注册 尽量在cpp文件注册，在.h文件注册可能会多次注册，不过也不会引起错误
#define REGISTER_HELPER_CLASS(Class, Key) \
    static WidgetHelperFactory::register_t<Class> _register_helper_##Class(Key);

#endif // WidgetHelper_H
